#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* openUBMC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*         http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.

IR TypeVar 节点定义
"""

import ast
from dataclasses import dataclass, field
from typing import List, Optional, Iterator

from mcpy.ir.module import IRModule
from ..base import IRNode
from ...symbol_table import Symbol, SymbolKind
from ...symbol_meta import TypeInfo, TypeKind
from mcpy.template_param import TemplateParam, ConstraintKind


@dataclass
class IRTypeVar(IRNode):
    """IR TypeVar 节点

    表示一个类型变量声明, 如 T = TypeVar("T")
    """

    # 类属性
    node_type: str = "typevar"

    name: str = field(default="")  # 类型变量名称, 如 "T"
    source_line: int = field(default=0)
    constraints: List[str] = field(
        default_factory=list
    )  # 类型约束, 如 TypeVar("T", int, str)
    bound: Optional[str] = field(
        default=None
    )  # 类型边界, 如 TypeVar("T", bound=Comparable)
    covariant: bool = field(default=False)  # 协变
    contravariant: bool = field(default=False)  # 逆变

    def to_template_param(self) -> TemplateParam:
        """将 IRTypeVar 转换为 TemplateParam

        这是 stub 体系与模板参数系统的集成点。
        IRTypeVar 来自 Python 的 TypeVar 定义，转换为统一的 TemplateParam 表示。

        Returns:
            TemplateParam 对象
        """
        # 确定约束类型
        if self.constraints:
            # 有 constraints 列表，使用 UNION 约束
            return TemplateParam(
                name=self.name,
                constraint_kind=ConstraintKind.UNION,
                allowed_types=self.constraints,
                description=f"TypeVar from stub/user code",
            )
        elif self.bound:
            # 有 bound，目前简化处理：暂不使用 PROTOCOL 约束
            # TODO: 未来可以更精细地处理 bound（如果 bound 是一个 Protocol，解析其方法）
            # 现在先作为无约束处理，但记录 bound 信息在描述中
            return TemplateParam(
                name=self.name,
                constraint_kind=ConstraintKind.NONE,
                description=f"TypeVar with bound={self.bound}",
            )
        else:
            # 无约束
            return TemplateParam(
                name=self.name,
                constraint_kind=ConstraintKind.NONE,
                description=f"TypeVar from stub/user code",
            )

    def new_symbol(self) -> "Symbol":
        """创建类型参数符号

        TypeVar 不是普通变量，而是类型参数（Type Parameter）。
        通过专门的 SymbolKind.TYPE_PARAM 和 TypeKind.TYPE_PARAM 来标识。
        """
        # 转换为 TemplateParam
        template_param = self.to_template_param()

        # 创建类型信息
        type_info = TypeInfo(
            kind=TypeKind.TYPE_PARAM,  # 类型参数类型
            name=self.name,
            template_constraints=self.constraints,
            template_bound=self.bound,
        )

        # 获取模块信息
        root_module = self.get_ir_module()
        assert root_module and isinstance(root_module, IRModule)
        module_name = root_module.module_full_name

        # 创建类型参数符号
        # 约束信息存储在 template_param 中，无需额外注册
        return Symbol(
            name=self.name,
            kind=SymbolKind.TYPE_PARAM,  # 类型参数（不是 VARIABLE）
            module=module_name,
            line=self.source_line,
            ir_node=self,
            type_info=type_info,
            template_params=[template_param],  # 存储约束信息
        )

    def get_local_symbols(self) -> Iterator[Symbol]:
        """获取 TypeVar 节点中定义的本地符号

        TypeVar 节点定义一个类型变量符号

        Returns:
            包含类型变量符号的迭代器
        """
        symbol = self.new_symbol()
        if symbol:
            yield symbol

    def build_from_ast(self, node: ast.Assign) -> None:
        """从 AST 赋值节点构建 IR TypeVar 节点内容

        处理形如 T = TypeVar("T", ...) 的赋值语句

        Args:
            node: AST 赋值节点
        """
        super().build_from_ast(node)

        if not isinstance(node, ast.Assign) or len(node.targets) != 1:
            raise ValueError("TypeVar must be a simple assignment")

        target = node.targets[0]
        if not isinstance(target, ast.Name):
            raise ValueError("TypeVar target must be a simple name")

        self.name = target.id
        self.source_line = getattr(node, "lineno", 0)

        # 解析 TypeVar 调用
        if isinstance(node.value, ast.Call):
            self._parse_typevar_call(node.value)

    def _parse_typevar_call(self, call_node: ast.Call) -> None:
        """解析 TypeVar 函数调用

        Args:
            call_node: TypeVar 函数调用的 AST 节点
        """
        # 检查是否是 TypeVar 调用
        if not (
            isinstance(call_node.func, ast.Name) and call_node.func.id == "TypeVar"
        ):
            return

        # 解析位置参数：第一个是名称，其余是约束
        if call_node.args:
            # 第一个参数应该是类型变量名称（字符串）
            if len(call_node.args) > 1:
                # 其余参数是类型约束
                for arg in call_node.args[1:]:
                    if isinstance(arg, ast.Name):
                        self.constraints.append(arg.id)
                    elif isinstance(arg, ast.Constant) and isinstance(arg.value, str):
                        self.constraints.append(arg.value)

        # 解析关键字参数
        for keyword in call_node.keywords:
            if keyword.arg == "bound":
                if isinstance(keyword.value, ast.Name):
                    self.bound = keyword.value.id
                elif isinstance(keyword.value, ast.Constant) and isinstance(
                    keyword.value.value, str
                ):
                    self.bound = keyword.value.value
            elif keyword.arg == "covariant":
                if isinstance(keyword.value, ast.Constant):
                    self.covariant = bool(keyword.value.value)
            elif keyword.arg == "contravariant":
                if isinstance(keyword.value, ast.Constant):
                    self.contravariant = bool(keyword.value.value)

    def get_type_info(self) -> TypeInfo:
        """获取类型参数的类型信息"""
        return TypeInfo(
            kind=TypeKind.TYPE_PARAM,  # 类型参数类型
            name=self.name,
            template_constraints=self.constraints,
            template_bound=self.bound,
        )

    def __str__(self) -> str:
        """字符串表示"""
        constraints_str = f", {', '.join(self.constraints)}" if self.constraints else ""
        bound_str = f", bound={self.bound}" if self.bound else ""
        covariant_str = ", covariant=True" if self.covariant else ""
        contravariant_str = ", contravariant=True" if self.contravariant else ""

        return f"TypeVar('{self.name}'{constraints_str}{bound_str}{covariant_str}{contravariant_str})"
